home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / et / et3_0-a1.lha / et3 / src / CollView.C < prev    next >
C/C++ Source or Header  |  1992-08-11  |  11KB  |  550 lines

  1. #ifdef __GNUG__
  2. #pragma implementation
  3. #endif
  4.  
  5. #include "CollView.h"
  6.  
  7. #include "Class.h"
  8. #include "String.h"
  9. #include "SeqColl.h"
  10. #include "VObject.h"
  11. #include "CmdNo.h"
  12. #include "Error.h"
  13. #include "Math.h"
  14. #include "WindowSystem.h"
  15.  
  16. extern bool testopen;
  17.  
  18. //---- CollectionView ----------------------------------------------------------
  19.  
  20. NewMetaImpl(CollectionView,View, (TP(coll), T(selection), T(gap), T(minExtent),
  21.                         T(rows), T(cols), TP(defaultItem)));
  22.  
  23. CollectionView::CollectionView(EvtHandler *eh, SeqCollection *m, CollViewOptions o,
  24.                         int r, int c) : View(eh, gRect0)
  25. {
  26.     SetFlag(o);
  27.     defaultItem= new VObject();
  28.     rows= r;
  29.     cols= c;
  30.     SetCollection(m);
  31. }
  32.  
  33. CollectionView::~CollectionView()
  34. {
  35.     if (coll) {
  36.     coll->RemoveObserver(this);
  37.     coll->FreeAll();
  38.     SafeDelete(coll);
  39.     }
  40.     SafeDelete(xPos);
  41.     SafeDelete(yPos);
  42.     SafeDelete(defaultItem);
  43. }
  44.  
  45. //---- init methods
  46.  
  47. void CollectionView::SetSelection(Rectangle newsel, bool sendcontrol)
  48. {
  49.     if (selection != newsel) {
  50.     if (IsOpen()) {
  51.         InvalidateRect(ItemRect(selection));
  52.         InvalidateRect(ItemRect(newsel));
  53.     }
  54.     selection= newsel;
  55.     }
  56.     if (sendcontrol)
  57.     DoSelect(selection, WindowSystem::Clicks);
  58. }
  59.  
  60. void CollectionView::SetColsRows(Point cr)
  61. {
  62.     cols= cr.x;
  63.     rows= cr.y;
  64.     Modified();
  65. }
  66.  
  67. void CollectionView::DoSelect(Rectangle r, int clicks)
  68. {
  69.     if (r.IsNotEmpty()) {
  70.     int partcode= clicks >= 2 ? cPartCollDoubleSelect : cPartCollSelect;
  71.     Control(GetId(), partcode, (void*) r.origin.y);
  72.     }
  73. }
  74.  
  75. void CollectionView::ClearSelection(bool)
  76. {
  77.     SetSelection(gRect0);
  78. }
  79.  
  80. void CollectionView::SetCollection(SeqCollection *m, bool freeold)
  81. {
  82.     if (coll) {
  83.     coll->RemoveObserver(this);
  84.     /*
  85.     {
  86.         coll->ForEach(VObject,Open)(FALSE);
  87.     }
  88.     */
  89.     {
  90.         coll->ForEach(VObject,ClearContainer)(this);
  91.     }
  92.     if (freeold) {
  93.         coll->FreeAll();
  94.         delete coll;
  95.     }
  96.     }
  97.     coll= m;
  98.     if (coll) {
  99.     coll->AssertClass(VObject);
  100.     {
  101.         coll->ForEach(VObject,SetContainer)(this);
  102.     }
  103.     if (IsOpen()) {
  104.         coll->ForEach(VObject,Open)(TRUE);
  105.     }
  106.     coll->AddObserver(this);
  107.     }
  108.     selection= gRect0;
  109.     Modified();
  110.     //if (IsOpen())
  111.     //    Scroll(cPartScrollAbs, gPoint0, FALSE);
  112. }
  113.  
  114. void CollectionView::SetDefaultItem(class VObject *d)
  115.     if (defaultItem)
  116.     delete defaultItem;
  117.     defaultItem= d;
  118. }
  119.  
  120. void CollectionView::SetMinExtent(Point e)
  121. {
  122.     if (minExtent != e) {
  123.     minExtent= e;
  124.     Modified();
  125.     }
  126. }
  127.  
  128. Metric CollectionView::GetMinSize()
  129. {
  130.     Update();
  131.     return GetExtent();
  132. }
  133.  
  134. void CollectionView::Open(bool m)
  135. {
  136.     View::Open(m);
  137.     if (testopen) {
  138.     if (m) {
  139.         if (coll) {
  140.         coll->ForEach(VObject,Open)(TRUE);
  141.         }
  142.     } else {
  143.         if (!IsOpen() && coll) {
  144.         coll->ForEach(VObject,Open)(FALSE);
  145.         }
  146.     }
  147.     }
  148. }
  149.  
  150. //---- layout
  151.  
  152. void CollectionView::ConstrainScroll(Point *p)
  153. {
  154.     if (xPos) {
  155.     bool outside;
  156.     Point pp= PointToItem(*p, &outside);
  157.     if (! outside)
  158.         p->y= ItemRect(0, pp.y).origin.y;
  159.     }
  160. }
  161.  
  162. void CollectionView::SetOrigin(Point at)
  163. {
  164.     View::SetOrigin(at);
  165.     if (coll && coll->Size() > 0) {
  166.     register int x, y;
  167.     at+= gap;
  168.     for (x= 0; x < cols; x++)
  169.         for (y= 0; y < rows; y++)
  170.         GetItem(x, y)->SetOrigin(Point(xPos[x]+at.x, yPos[y]+at.y));
  171.     }
  172. }
  173.  
  174. void CollectionView::Update()
  175. {
  176.     register VObject *gop;
  177.     register int x, y, ww, hh, w, h;
  178.     int xpos= 0, ypos= 0, sz;
  179.     Point g;
  180.  
  181.     if (!TestFlag(eCVModified))
  182.     return;
  183.     ResetFlag(eCVModified);
  184.  
  185.     if (coll == 0 || coll->Size() <= 0) {
  186.     ForceRedraw();
  187.     return;
  188.     }
  189.     
  190.     if (testopen) {
  191.     {
  192.         coll->ForEach(VObject,SetContainer)(this);
  193.     }
  194.     if (IsOpen()) {
  195.         coll->ForEach(VObject,Open)(TRUE);
  196.     }
  197.     }
  198.     
  199.     sz= coll->Size();
  200.     if (rows <= 0)
  201.     SetFlag(eCVExpandRows);
  202.     if (cols <= 0)
  203.     SetFlag(eCVExpandCols);
  204.     
  205.     if (TestFlag(eCVExpandRows) && TestFlag(eCVExpandCols)) {
  206.     cols= Math::Sqrt(sz);
  207.     rows= (sz+cols-1) / cols;
  208.     } else if (TestFlag(eCVExpandRows))
  209.     rows= (sz+cols-1) / cols;
  210.     else if (TestFlag(eCVExpandCols))
  211.     cols= (sz+rows-1) / rows;
  212.  
  213.     yPos= (int*) Realloc(yPos, (rows+1) * sizeof(int));
  214.     xPos= (int*) Realloc(xPos, (cols+1) * sizeof(int));
  215.  
  216.     xpos= ypos= 0;
  217.     g= 2*gap;
  218.     if (TestFlag(eCVGrid))
  219.     g+= gPoint1;
  220.     
  221.     for (x= 0; x < cols; x++) {
  222.     xPos[x]= xpos;
  223.     ww= minExtent.x;
  224.     for (y= 0; y < rows; y++) {
  225.         gop= GetItem(x, y);
  226.         gop->SetContainer(this);
  227.         if (!testopen) {
  228.         if (IsOpen())
  229.             gop->Open();
  230.         }
  231.         gop->CalcExtent();
  232.         w= gop->Width();
  233.         ww= Math::Max(ww, w);
  234.     }
  235.     xpos+= ww+g.x;
  236.     }
  237.     xPos[x]= xpos;
  238.  
  239.     for (y= 0; y < rows; y++) {
  240.     yPos[y]= ypos;
  241.     hh= minExtent.y;
  242.     for (x= 0; x < cols; x++) {
  243.         h= GetItem(x, y)->Height();
  244.         hh= Math::Max(hh, h);
  245.     }
  246.     ypos+= hh+g.y;
  247.     }
  248.     yPos[y]= ypos;
  249.  
  250.     for (x= 0; x < cols; x++)
  251.     for (y= 0; y < rows; y++)
  252.         GetItem(x, y)->SetContentRect(ItemRect(x, y).Inset(gap), FALSE);
  253.  
  254.     if (TestFlag(eCVGrid)) {
  255.     xpos--;
  256.     ypos--;
  257.     }
  258.     
  259.     ForceRedraw();
  260.     SetExtent(Point(xpos, ypos));
  261.     ForceRedraw();
  262. }
  263.  
  264. //---- update
  265.  
  266. void CollectionView::DoObserve(int, int part, void *, Object *op)
  267. {
  268.     if (part == cPartSenderDied)
  269.     coll= 0;
  270.     else if (op == coll)
  271.     Modified();
  272. }
  273.  
  274. void CollectionView::Modified()
  275. {
  276.     SetFlag(eCVModified);
  277.     if (IsOpen())
  278.     Update();
  279. }
  280.  
  281. //---- mapping
  282.  
  283. Point CollectionView::PointToItem(Point p, bool *outside)
  284. {
  285.     register int x, y;
  286.     register bool out= FALSE;
  287.     
  288.     if (coll == 0 || coll->Size() <= 0) {
  289.     if (outside)
  290.         *outside= TRUE;
  291.     return gPoint0;
  292.     }
  293.     Update();
  294.     p-= GetOrigin();
  295.     if (p.x < xPos[0]) {
  296.     out= TRUE;
  297.     x= 0;
  298.     } else if (p.x >= xPos[cols]) {
  299.     out= TRUE;
  300.     x= cols-1;
  301.     } else {
  302.     for (x= 0; x < cols; x++)
  303.         if (p.x >= xPos[x] && p.x < xPos[x+1])
  304.         break;
  305.     }
  306.     if (p.y < yPos[0]) {
  307.     out= TRUE;
  308.     y= 0;
  309.     } else if (p.y >= yPos[rows]) {
  310.     out= TRUE;
  311.     y= rows-1;
  312.     } else {
  313.     for (y= 0; y < rows; y++)
  314.         if (p.y >= yPos[y] && p.y < yPos[y+1])
  315.         break;
  316.     }
  317.     if (outside)
  318.     *outside= out;
  319.     return Point(x, y);
  320. }
  321.  
  322. Rectangle CollectionView::ItemRect(Rectangle r)
  323. {
  324.     Rectangle rr;
  325.  
  326.     if (r.IsEmpty())
  327.     return gRect0;
  328.     Update();
  329.     rr.origin.x= xPos[r.origin.x];
  330.     rr.origin.y= yPos[r.origin.y];
  331.     rr.extent.x= xPos[r.origin.x+r.extent.x] - rr.origin.x;
  332.     rr.extent.y= yPos[r.origin.y+r.extent.y] - rr.origin.y;
  333.     if (TestFlag(eCVGrid))
  334.     rr.extent-= gPoint1;
  335.     return rr+GetOrigin();
  336. }
  337.  
  338. Point CollectionView::ItemPos(VObject *g)
  339. {
  340.     VObject *gop;
  341.     Iter next(coll);
  342.  
  343.     Update();
  344.     for (int i= 0; gop= (VObject*) next(); i++)
  345.     if (gop == g)
  346.         break;
  347.     if (i >= coll->Size())
  348.     return gPoint_1;
  349.     return Point(i % cols, i / cols);
  350. }
  351.  
  352. Rectangle CollectionView::ItemRect(int x, int y)
  353. {
  354.     Update();
  355.     x= Math::Range(0, cols-1, x);
  356.     y= Math::Range(0, rows-1, y);
  357.     Rectangle r(xPos[x], yPos[y], xPos[x+1]-xPos[x], yPos[y+1]-yPos[y]);
  358.     if (TestFlag(eCVGrid))
  359.     r.extent-= gPoint1;
  360.     r.origin+= GetOrigin();
  361.     return r;
  362. }
  363.  
  364. VObject *CollectionView::GetItem(int x, int y)
  365. {
  366.     VObject *vop= 0;
  367.     int ix= y*cols+x;
  368.     
  369.     if (ix >= 0 && ix < coll->Size())
  370.     vop= (VObject*)coll->At(ix);
  371.     return vop ? vop : defaultItem;
  372. }
  373.  
  374. //---- event handlung
  375.  
  376. Command *CollectionView::DoLeftButtonDownCommand(Point lp, Token t, int clicks)
  377. {
  378.     if (coll && coll->Size() > 0) {
  379.     ClearSelection();
  380.     return new CellSelector(this, TestFlag(eCVDontStuckToBorder));
  381.     }
  382.     return View::DoLeftButtonDownCommand(lp, t, clicks);
  383. }
  384.  
  385. Command *CollectionView::DoKeyCommand(int ch, Token)
  386. {
  387.     register VObject *gop= 0;
  388.     register int i;
  389.     int start= 0;
  390.     Rectangle r= GetViewedRect();
  391.     
  392.     if (r.IsNotEmpty()) {
  393.     start= r.origin.y+r.extent.y;
  394.     if (start <= GetExtent().y)
  395.         start= PointToItem(Point(0,start)).y;
  396.     }
  397.  
  398.     for (i= 0; i < rows; i++) {
  399.     gop= GetItem(0, (start+i) % rows);
  400.     if (gop && (sortmap[gop->AsString()[0]] == sortmap[ch]))
  401.         break;
  402.     }
  403.  
  404.     if (gop)
  405.     RevealAlign(ItemRect(Rectangle(ItemPos(gop), gPoint1)));
  406.     return gNoChanges;
  407. }
  408.  
  409. //---- drawing
  410.  
  411. void CollectionView::Draw(Rectangle r)
  412. {
  413.     register int x, y;
  414.     register VObject *gop;
  415.     Point p1, p2;
  416.  
  417.     if (coll == 0 || coll->Size() <= 0)
  418.     return;
  419.     p1= PointToItem(r.NW());
  420.     p2= PointToItem(r.SE()+gPoint1);
  421.     int i= 0;
  422.     for (x= p1.x; x <= p2.x; x++) {
  423.     for (y= p1.y; y <= p2.y; y++) {
  424.         i++;
  425.         gop= GetItem(x, y);
  426.         gop->DrawAll(gop->contentRect,
  427.             selection.ContainsPoint(Point(x, y)) && gop->Enabled());
  428.     }
  429.     }
  430.     if (TestFlag(eCVGrid)) {
  431.     GrSetPenNormal();
  432.     DrawGrid(p1, p2);
  433.     }
  434.  
  435. void CollectionView::DrawGrid(Point p1, Point p2)
  436. {
  437.     register int x, y;
  438.     int xx= 0, yy= 0;
  439.     Point o= GetOrigin();
  440.  
  441.     if (p2.x >= cols-1)
  442.     xx= 1;
  443.     if (p2.y >= rows-1)
  444.     yy= 1;
  445.     for (x= p1.x; x <= p2.x-xx; x++)
  446.     GrLine(Point(xPos[x+1]-1, yPos[p1.y])+o, Point(xPos[x+1]-1, yPos[p2.y+1]-1)+o);
  447.     for (y= p1.y; y <= p2.y-yy; y++)
  448.     GrLine(Point(xPos[p1.x], yPos[y+1]-1)+o, Point(xPos[p2.x+1]-1, yPos[y+1]-1)+o);
  449. }
  450.  
  451. //---- input/output
  452.  
  453. OStream& CollectionView::PrintOn(OStream &s)
  454. {
  455.     Object::PrintOn(s);
  456.     return s << gap SP << minExtent SP << rows SP << cols SP << defaultItem SP << coll SP;
  457. }
  458.  
  459. bool CollectionView::PrintOnWhenObserving(Object *from)
  460. {
  461.     return from != coll;
  462. }
  463.  
  464. IStream& CollectionView::ReadFrom(IStream &s)
  465. {
  466.     SeqCollection *m;
  467.     VObject *di= 0;
  468.  
  469.     Object::ReadFrom(s);
  470.     s >> gap >> minExtent >> rows >> cols >> di >> m;
  471.     SetCollection(m);
  472.     SetDefaultItem(di);
  473.     return s;
  474. }
  475.  
  476. void CollectionView::CollectParts(Collection* col)
  477. {
  478.     View::CollectParts(col);
  479.     if (coll && coll->Size() < 12) // hack
  480.     col->Add(coll);
  481. }
  482.  
  483. VObject *CollectionView::Detect(BoolFun find, void *arg)
  484. {
  485.     if (coll) {
  486.     Iter next(coll);
  487.     register VObject *v1, *v2;
  488.  
  489.     while (v1= (VObject*) next())
  490.         if (v2= v1->Detect(find, arg))
  491.         return v2;
  492.     }
  493.     return 0;
  494. }
  495.  
  496. //---- CellSelector ------------------------------------------------------------
  497.  
  498. CellSelector::CellSelector(CollectionView* v, bool dontstucktoborder)
  499.     SetFlag(eCmdNoReplFeedback);
  500.     lvp= v;
  501.     last= 0;
  502.     dontstuck= dontstucktoborder;
  503. }
  504.  
  505. void CellSelector::TrackFeedback(Point, Point pp, bool on)
  506. {
  507.     if (on) {
  508.     if (itemptr == last) {
  509.         if (last)
  510.         last->DoTrackMouse((TrackPhase)eTrackMove, pp);
  511.     } else {
  512.         if (last)
  513.         last->DoTrackMouse((TrackPhase)eTrackRelease, pp);
  514.         if (itemptr)
  515.         itemptr->DoTrackMouse((TrackPhase)eTrackPress, pp);
  516.     }
  517.     last= itemptr;
  518.     }
  519. }
  520.  
  521. Command *CellSelector::TrackMouse(TrackPhase atp, Point, Point, Point np)
  522. {
  523.     bool outside= FALSE;
  524.     
  525.     item= lvp->PointToItem(np, &outside);
  526.     if (outside && dontstuck)
  527.     itemptr= 0;
  528.     else
  529.     itemptr= lvp->GetItem(item.x, item.y);
  530.     
  531.     switch (atp) {
  532.     case eTrackRelease:
  533.     if (last)
  534.         last->DoTrackMouse((TrackPhase)eTrackRelease, np);
  535.     if (itemptr && itemptr->Enabled())
  536.         lvp->SetSelection(Rectangle(item, gPoint1), TRUE);
  537.     else
  538.         lvp->SetSelection(gRect0, TRUE);
  539.     case eTrackExit:
  540.     return gNoChanges;
  541.     default:
  542.     break;
  543.     }
  544.     return this;
  545. }
  546.  
  547.